<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <title>【网络基础】SSL双向认证 | 狼组安全团队公开知识库</title>
    <meta name="description" content="">
    <meta name="generator" content="VuePress 1.7.1">
    <link rel="icon" href="/assets/logo.svg">
    <script type="text/javascript" src="/assets/js/push.js"></script>
    <meta name="description" content="致力于打造信息安全乌托邦">
    <meta name="referrer" content="never">
    <meta name="keywords" content="知识库,公开知识库,狼组,狼组安全团队知识库,knowledge">
    <link rel="preload" href="/assets/css/0.styles.32ca519c.css" as="style"><link rel="preload" href="/assets/js/app.f7464420.js" as="script"><link rel="preload" href="/assets/js/2.26207483.js" as="script"><link rel="preload" href="/assets/js/19.19350186.js" as="script"><link rel="prefetch" href="/assets/js/10.55514509.js"><link rel="prefetch" href="/assets/js/11.ec576042.js"><link rel="prefetch" href="/assets/js/12.a5584a2f.js"><link rel="prefetch" href="/assets/js/13.c9f84b2e.js"><link rel="prefetch" href="/assets/js/14.d2a5440c.js"><link rel="prefetch" href="/assets/js/15.2f271296.js"><link rel="prefetch" href="/assets/js/16.0895ce42.js"><link rel="prefetch" href="/assets/js/17.627e2976.js"><link rel="prefetch" href="/assets/js/18.73745a4c.js"><link rel="prefetch" href="/assets/js/20.e4eac589.js"><link rel="prefetch" href="/assets/js/21.fc0657ba.js"><link rel="prefetch" href="/assets/js/22.f4a1220f.js"><link rel="prefetch" href="/assets/js/23.c8cce92d.js"><link rel="prefetch" href="/assets/js/24.46225ec2.js"><link rel="prefetch" href="/assets/js/25.9b6d75e4.js"><link rel="prefetch" href="/assets/js/26.288f535e.js"><link rel="prefetch" href="/assets/js/27.865bdc75.js"><link rel="prefetch" href="/assets/js/28.f4224fef.js"><link rel="prefetch" href="/assets/js/29.6393a40b.js"><link rel="prefetch" href="/assets/js/3.a509f503.js"><link rel="prefetch" href="/assets/js/30.d5a49f97.js"><link rel="prefetch" href="/assets/js/31.eb3647df.js"><link rel="prefetch" href="/assets/js/32.7f48a571.js"><link rel="prefetch" href="/assets/js/33.1f374ffa.js"><link rel="prefetch" href="/assets/js/34.5a911179.js"><link rel="prefetch" href="/assets/js/35.d2bcc7ef.js"><link rel="prefetch" href="/assets/js/36.42e440bd.js"><link rel="prefetch" href="/assets/js/37.dedbbdea.js"><link rel="prefetch" href="/assets/js/38.d68d1f69.js"><link rel="prefetch" href="/assets/js/39.e278f860.js"><link rel="prefetch" href="/assets/js/4.35636da8.js"><link rel="prefetch" href="/assets/js/40.97f4e937.js"><link rel="prefetch" href="/assets/js/41.38630688.js"><link rel="prefetch" href="/assets/js/42.cae56aa5.js"><link rel="prefetch" href="/assets/js/43.61a04b16.js"><link rel="prefetch" href="/assets/js/44.5c6230f2.js"><link rel="prefetch" href="/assets/js/45.0f1355ae.js"><link rel="prefetch" href="/assets/js/46.c1906649.js"><link rel="prefetch" href="/assets/js/47.7ae220ce.js"><link rel="prefetch" href="/assets/js/48.59af224e.js"><link rel="prefetch" href="/assets/js/49.6a33a171.js"><link rel="prefetch" href="/assets/js/5.08ab40ee.js"><link rel="prefetch" href="/assets/js/50.f14601d2.js"><link rel="prefetch" href="/assets/js/51.f20841fd.js"><link rel="prefetch" href="/assets/js/52.fb0a5327.js"><link rel="prefetch" href="/assets/js/53.8013048c.js"><link rel="prefetch" href="/assets/js/54.d132c2f8.js"><link rel="prefetch" href="/assets/js/55.87aa8b5d.js"><link rel="prefetch" href="/assets/js/56.161f38ad.js"><link rel="prefetch" href="/assets/js/57.bd6a2ef2.js"><link rel="prefetch" href="/assets/js/58.8a69f15a.js"><link rel="prefetch" href="/assets/js/59.93c0e2de.js"><link rel="prefetch" href="/assets/js/6.fda5ce3a.js"><link rel="prefetch" href="/assets/js/60.10091d44.js"><link rel="prefetch" href="/assets/js/61.cd1e3b10.js"><link rel="prefetch" href="/assets/js/62.9c0ad8c5.js"><link rel="prefetch" href="/assets/js/63.4a8dd9d2.js"><link rel="prefetch" href="/assets/js/64.6bf3fede.js"><link rel="prefetch" href="/assets/js/65.7a2ccc50.js"><link rel="prefetch" href="/assets/js/66.874d563b.js"><link rel="prefetch" href="/assets/js/67.bb86eab2.js"><link rel="prefetch" href="/assets/js/68.c1db2a2b.js"><link rel="prefetch" href="/assets/js/69.8141480b.js"><link rel="prefetch" href="/assets/js/7.d1fe6bef.js"><link rel="prefetch" href="/assets/js/70.9fb74c80.js"><link rel="prefetch" href="/assets/js/71.d1e4e9ab.js"><link rel="prefetch" href="/assets/js/72.e6bf83fb.js"><link rel="prefetch" href="/assets/js/73.6dd6c980.js"><link rel="prefetch" href="/assets/js/74.3612ba47.js"><link rel="prefetch" href="/assets/js/75.6e1a2434.js"><link rel="prefetch" href="/assets/js/76.5bfa4bcc.js"><link rel="prefetch" href="/assets/js/77.784df031.js"><link rel="prefetch" href="/assets/js/78.aa94a0a0.js"><link rel="prefetch" href="/assets/js/79.c4e9a4f2.js"><link rel="prefetch" href="/assets/js/8.63fd05d7.js"><link rel="prefetch" href="/assets/js/80.8d47d1f7.js"><link rel="prefetch" href="/assets/js/81.1160b022.js"><link rel="prefetch" href="/assets/js/82.7d17e5c8.js"><link rel="prefetch" href="/assets/js/83.a2ff144a.js"><link rel="prefetch" href="/assets/js/84.53d29383.js"><link rel="prefetch" href="/assets/js/9.b49161a4.js">
    <link rel="stylesheet" href="/assets/css/0.styles.32ca519c.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="ant-row"><div class="nav-button"><i aria-label="icon: bars" class="anticon anticon-bars"><svg viewBox="0 0 1024 1024" focusable="false" data-icon="bars" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M912 192H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 284H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 284H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM104 228a56 56 0 1 0 112 0 56 56 0 1 0-112 0zm0 284a56 56 0 1 0 112 0 56 56 0 1 0-112 0zm0 284a56 56 0 1 0 112 0 56 56 0 1 0-112 0z"></path></svg></i> <span></span></div> <div class="ant-col ant-col-xs-24 ant-col-sm-24 ant-col-md-6 ant-col-lg-5 ant-col-xl-5 ant-col-xxl-4"><a href="/" class="router-link-active home-link"><img src="/assets/logo.svg" alt="狼组安全团队公开知识库" class="logo"> <span class="site-name">狼组安全团队公开知识库</span></a> <div class="search-box mobile-search"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div></div> <div class="ant-col ant-col-xs-0 ant-col-sm-0 ant-col-md-18 ant-col-lg-19 ant-col-xl-19 ant-col-xxl-20"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><ul role="menu" id="nav" class="ant-menu ant-menu-horizontal ant-menu-root ant-menu-light"><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display:none;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li><li role="menuitem" class="ant-menu-item"><a href="/" class="router-link-active">
          首页
        </a></li><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display:none;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li><li role="menuitem" class="ant-menu-item"><a href="/guide/">
          使用指南
        </a></li><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display:none;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li><li role="menuitem" class="ant-menu-item"><a href="/knowledge/" class="router-link-active">
          知识库
        </a></li><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display:none;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li><li role="menuitem" class="ant-menu-item"><a href="/opensource/">
          开源项目
        </a></li><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="visibility:hidden;position:absolute;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li></ul> <a href="https://github.com/wgpsec" target="_blank" rel="noopener noreferrer" class="repo-link"><i aria-label="icon: github" class="anticon anticon-github"><svg viewBox="64 64 896 896" focusable="false" data-icon="github" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M511.6 76.3C264.3 76.2 64 276.4 64 523.5 64 718.9 189.3 885 363.8 946c23.5 5.9 19.9-10.8 19.9-22.2v-77.5c-135.7 15.9-141.2-73.9-150.3-88.9C215 726 171.5 718 184.5 703c30.9-15.9 62.4 4 98.9 57.9 26.4 39.1 77.9 32.5 104 26 5.7-23.5 17.9-44.5 34.7-60.8-140.6-25.2-199.2-111-199.2-213 0-49.5 16.3-95 48.3-131.7-20.4-60.5 1.9-112.3 4.9-120 58.1-5.2 118.5 41.6 123.2 45.3 33-8.9 70.7-13.6 112.9-13.6 42.4 0 80.2 4.9 113.5 13.9 11.3-8.6 67.3-48.8 121.3-43.9 2.9 7.7 24.7 58.3 5.5 118 32.4 36.8 48.9 82.7 48.9 132.3 0 102.2-59 188.1-200 212.9a127.5 127.5 0 0 1 38.1 91v112.5c.8 9 0 17.9 15 17.9 177.1-59.7 304.6-227 304.6-424.1 0-247.2-200.4-447.3-447.5-447.3z"></path></svg></i></a></nav></div></div> <!----></header> <aside class="sidebar"><div><div class="promo"><div id="promo_3"><div class="promo_title">赞助商</div> <button type="button" class="ant-btn ant-btn-primary ant-btn-background-ghost"><span>成为赞助商</span></button></div></div> <div role="separator" id="reset-margin" class="ant-divider ant-divider-horizontal ant-divider-dashed"></div></div> <ul class="sidebar-links"><li><a href="/knowledge/" aria-current="page" title="知识库广告位招租" class="sidebar-link">知识库广告位招租</a></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>CTF</span> <span class="arrow right"><i aria-label="icon: down" class="anticon anticon-down"><svg viewBox="64 64 896 896" focusable="false" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>基础知识</span> <span class="arrow down"><i aria-label="icon: down" class="anticon anticon-down"><svg viewBox="64 64 896 896" focusable="false" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/knowledge/base/" aria-current="page" title="分类简介" class="sidebar-link">分类简介</a></li><li><a href="/knowledge/base/safety.html" title="网络安全设备常识" class="sidebar-link">网络安全设备常识</a></li><li><a href="/knowledge/base/network-web.html" title="【网络基础】Web应用常识" class="sidebar-link">【网络基础】Web应用常识</a></li><li><a href="/knowledge/base/network-tcp-ip.html" title="【网络基础】TCP/IP协议" class="sidebar-link">【网络基础】TCP/IP协议</a></li><li><a href="/knowledge/base/network-http.html" title="【网络基础】HTTP协议" class="sidebar-link">【网络基础】HTTP协议</a></li><li><a href="/knowledge/base/network-https.html" aria-current="page" title="【网络基础】SSL双向认证" class="active sidebar-link">【网络基础】SSL双向认证</a></li><li><a href="/knowledge/base/network-route.html" title="【网络基础】路由协议" class="sidebar-link">【网络基础】路由协议</a></li><li><a href="/knowledge/base/linux-cmd.html" title="【操作系统】Linux基础命令" class="sidebar-link">【操作系统】Linux基础命令</a></li><li><a href="/knowledge/base/linux-awk.html" title="【操作系统】Linux三剑客" class="sidebar-link">【操作系统】Linux三剑客</a></li><li><a href="/knowledge/base/git-base.html" title="Git基本用法" class="sidebar-link">Git基本用法</a></li><li><a href="/knowledge/base/docker-base.html" title="Docker微服务构建指南" class="sidebar-link">Docker微服务构建指南</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>工具手册</span> <span class="arrow right"><i aria-label="icon: down" class="anticon anticon-down"><svg viewBox="64 64 896 896" focusable="false" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Web安全</span> <span class="arrow right"><i aria-label="icon: down" class="anticon anticon-down"><svg viewBox="64 64 896 896" focusable="false" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>攻防对抗</span> <span class="arrow right"><i aria-label="icon: down" class="anticon anticon-down"><svg viewBox="64 64 896 896" focusable="false" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>代码审计</span> <span class="arrow right"><i aria-label="icon: down" class="anticon anticon-down"><svg viewBox="64 64 896 896" focusable="false" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></p> <!----></section></li></ul></aside> <main class="page"> <div class="theme-antdocs-content content__default"><h1 id="https单向认证和双向认证">Https单向认证和双向认证 <a href="#https单向认证和双向认证" class="header-anchor">#</a></h1> <p><strong>SSL/TLS是同一个东西的不同阶段</strong></p> <blockquote><p>SSL 是英文 “Secure Sockets Layer” 的缩写，中文叫做“安全套接层”。</p> <p>它是在上世纪90年代中期，由网景公司设计的。</p> <p>到了1999年，<code>SSL</code> 因为应用广泛，已经成为互联网上的事实标准。</p> <p>IETF 就在那年把 <code>SSL</code> 标准化，标准化之后的名称改为 TLS；</p> <p>是“Transport Layer Security”的缩写，中文叫做 “传输层安全协议”。</p></blockquote> <h2 id="https利用对称与非对称加密算法结合的方式"><code>HTTPS</code>利用对称与非对称加密算法结合的方式 <a href="#https利用对称与非对称加密算法结合的方式" class="header-anchor">#</a></h2> <blockquote><p><strong>对称加密</strong>：</p> <p>就是通信双方使用一个密钥；该密钥既用于数据加密（发送方），也用于数据解密（接收方）</p> <p>速度高，可加密内容较大，用来加密会话过程中的消息</p> <p><strong>非对称加密</strong>：</p> <p>使用两个密钥；发送方使用公钥（公开密钥）对数据进行加密，数据接收方使用私钥对数据进行解密</p> <p>速度慢，但能提供更好的身份认证技术，用来加密对称加密的密钥</p></blockquote> <h2 id="https连接建立过程"><code>HTTPS</code>连接建立过程： <a href="#https连接建立过程" class="header-anchor">#</a></h2> <blockquote><p>1、客户端发送支持的加密协议及版本，<code>SSL</code>、<code>TLS</code>（传输层安全性协议：<code>SSL</code>是<code>TLS</code>的前身）</p> <p>2、服务器从中筛选合适的加密协议</p> <p>3、服务器端返回证书，证书中有公钥</p> <p>4、客户端使用根证书验证证书合法性</p> <p>5、客户端生成对称密钥，通过证书中的公钥加密，发送到服务端</p> <p>6、服务端使用私钥解密，获取对称密钥，使用对称密钥加密数据</p> <p>7、客户端解密数据，<code>SSL</code>加密通信建立，开始通信......</p></blockquote> <p><code>HTTPS</code>使用携带公钥信息的数字证书来保证公钥的安全性和完整性，并非直接传输公钥信息</p> <h2 id="单向认证">单向认证： <a href="#单向认证" class="header-anchor">#</a></h2> <blockquote><p>1、客户端发送SSL协议版本等信息</p> <p>2、服务端返回SSL版本、随机数信息、以及服务器公钥(在ca证书中)</p> <p>3、客户端使用根证书校验服务端证书合法性，合法继续，否则警告</p> <p>4、客户端发送自己可支持的对称加密方案给服务端，供其选择</p> <p>5、服务端选择加密程度高的方案</p> <p>6、服务端将选择好的加密方案，明文发送给客户端</p> <p>7、客户端收到加密方案，产生随机码，作为对称加密密钥，用服务端公钥加密，发给服务端</p> <p>8、服务端使用私钥解密，获得对称加密密钥</p> <p>9、对称加密通信数据，开始通信</p></blockquote> <h2 id="双向认证">双向认证： <a href="#双向认证" class="header-anchor">#</a></h2> <p>双向认证和单向认证原理差不多，只是除了客户端需要认证服务端以外，增加了服务端对客户端的认证。</p> <blockquote><p>1、客户端发送SSL协议版本等信息</p> <p>2、服务端返回SSL版本、随机数信息、以及服务器公钥(在ca证书中)</p> <p>3、客户端使用根证书校验服务端证书合法性，合法继续，否则警告</p> <p><strong>4、客户端通过校验后，将自己的证书和公钥发给服务端</strong></p> <p><strong>5、服务端校验证书，获得客户端公钥</strong></p> <p>6、客户端发送自己可支持的对称加密方案给服务端，供其选择</p> <p>7、服务端选择加密程度高的方案</p> <p>8、服务端将选择好的加密方案，<strong>使用客户端公钥加密后</strong>，发送给客户端</p> <p>9、客户端收到加密方案，产生随机码，作为对称加密密钥，用服务端公钥加密，发给服务端</p> <p>10、服务端使用私钥解密，获得对称加密密钥</p> <p>11、对称加密通信数据，开始通信</p></blockquote> <h1 id="实验使用golang模拟单向认证和双向认证">实验使用Golang模拟单向认证和双向认证 <a href="#实验使用golang模拟单向认证和双向认证" class="header-anchor">#</a></h1> <p>Go语言中有标准库<code>crypto/x509软件包</code>， 用于分析 <code>X.509</code> 编码的密钥和证书</p> <p>安装golang：https://studygolang.com/articles/6165</p> <p>Go手册：https://cloud.tencent.com/developer/doc/1101</p> <p>入门教程：https://github.com/jackhu1990/golangman</p> <h2 id="单向认证-对服务端证书进行校验">单向认证，对服务端证书进行校验 <a href="#单向认证-对服务端证书进行校验" class="header-anchor">#</a></h2> <p><strong>自签发证书，生成根证书</strong></p> <p>根证书是CA认证中心给自己颁发的证书,是信任链的起始点.</p> <p>这里我们自己做CA使用<code>openssl</code>命令来生成根证书.</p> <p>首先建立我们自己的CA，需要生成一个CA私钥和一个CA的数字证书</p> <p><strong>生成CA私钥和CA证书</strong></p> <div class="language-bash line-numbers-mode"><pre class="language-bash"><code>openssl genrsa -out ca.key <span class="token number">2048</span>
openssl req -x509 -new -nodes -key ca.key -subj <span class="token string">&quot;/CN=wintrysec_com&quot;</span> -days <span class="token number">5000</span> -out ca.crt
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p><strong>然后生成server端的私钥，生成数字证书请求，并用我们的ca私钥签发server的数字证书</strong></p> <p>开始生成<code>X509</code>格式的自签名证书,会要求输入各项信息（国家，省份，城市，组织，姓名，email等 )</p> <div class="language-bash line-numbers-mode"><pre class="language-bash"><code>openssl genrsa -out server.key <span class="token number">2048</span>
openssl req -new -key server.key -subj <span class="token string">&quot;/CN=localhost&quot;</span> -out server.csr
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days <span class="token number">5000</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>现在我们的工作目录下，有以下私钥和证书文件：</p> <blockquote><p>CA:</p> <p>​	私钥文件 <code>ca.key</code></p> <p>​	数字证书<code>ca.crt</code></p> <p>Server:</p> <p>​	私钥文件 <code>server.key</code></p> <p>​	数字证书 <code>server.crt</code></p></blockquote> <p><strong>服务端程序，<code>server.go</code>:</strong></p> <div class="language-go line-numbers-mode"><pre class="language-go"><code><span class="token comment">// server.go</span>
<span class="token keyword">package</span> main

<span class="token keyword">import</span> <span class="token punctuation">(</span>
    <span class="token string">&quot;fmt&quot;</span>
    <span class="token string">&quot;net/http&quot;</span>
<span class="token punctuation">)</span>

<span class="token comment">//定义Web服务器</span>
<span class="token keyword">func</span> <span class="token function">handler</span><span class="token punctuation">(</span>w http<span class="token punctuation">.</span>ResponseWriter<span class="token punctuation">,</span> r <span class="token operator">*</span>http<span class="token punctuation">.</span>Request<span class="token punctuation">)</span> 
<span class="token punctuation">{</span>
    fmt<span class="token punctuation">.</span><span class="token function">Fprintf</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span><span class="token string">&quot;这是HTTPS服务器页面，单向认证完成，我们可以通信了！&quot;</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    http<span class="token punctuation">.</span><span class="token function">HandleFunc</span><span class="token punctuation">(</span><span class="token string">&quot;/&quot;</span><span class="token punctuation">,</span> handler<span class="token punctuation">)</span>
    http<span class="token punctuation">.</span><span class="token function">ListenAndServeTLS</span><span class="token punctuation">(</span><span class="token string">&quot;:8081&quot;</span><span class="token punctuation">,</span>
        <span class="token string">&quot;server.crt&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;server.key&quot;</span><span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">)</span>
        <span class="token comment">//ListenAndServeTLS需要HTTPS连接，必须提供包含服务器证书和匹配私钥的文件</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><p><strong>客户端程序，<code>client.go</code>:</strong></p> <div class="language-go line-numbers-mode"><pre class="language-go"><code><span class="token comment">//client.go</span>
<span class="token keyword">package</span> main

<span class="token keyword">import</span> <span class="token punctuation">(</span>
    <span class="token string">&quot;crypto/tls&quot;</span>
    <span class="token string">&quot;crypto/x509&quot;</span>
    <span class="token string">&quot;fmt&quot;</span>
    <span class="token string">&quot;io/ioutil&quot;</span>
    <span class="token string">&quot;net/http&quot;</span>
<span class="token punctuation">)</span>

<span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    pool <span class="token operator">:=</span> x509<span class="token punctuation">.</span><span class="token function">NewCertPool</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    caCertPath <span class="token operator">:=</span> <span class="token string">&quot;ca.crt&quot;</span>

    caCrt<span class="token punctuation">,</span> err <span class="token operator">:=</span> ioutil<span class="token punctuation">.</span><span class="token function">ReadFile</span><span class="token punctuation">(</span>caCertPath<span class="token punctuation">)</span>
    <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
        fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">&quot;ReadFile err:&quot;</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
        <span class="token keyword">return</span>
    <span class="token punctuation">}</span>
    pool<span class="token punctuation">.</span><span class="token function">AppendCertsFromPEM</span><span class="token punctuation">(</span>caCrt<span class="token punctuation">)</span>

    tr <span class="token operator">:=</span> <span class="token operator">&amp;</span>http<span class="token punctuation">.</span>Transport<span class="token punctuation">{</span>
        TLSClientConfig<span class="token punctuation">:</span> <span class="token operator">&amp;</span>tls<span class="token punctuation">.</span>Config<span class="token punctuation">{</span>RootCAs<span class="token punctuation">:</span> pool<span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span>
    client <span class="token operator">:=</span> <span class="token operator">&amp;</span>http<span class="token punctuation">.</span>Client<span class="token punctuation">{</span>Transport<span class="token punctuation">:</span> tr<span class="token punctuation">}</span>
    resp<span class="token punctuation">,</span> err <span class="token operator">:=</span> client<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span><span class="token string">&quot;https://localhost:8081&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
        fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">&quot;Get error:&quot;</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
        <span class="token keyword">return</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">defer</span> resp<span class="token punctuation">.</span>Body<span class="token punctuation">.</span><span class="token function">Close</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    body<span class="token punctuation">,</span> err <span class="token operator">:=</span> ioutil<span class="token punctuation">.</span><span class="token function">ReadAll</span><span class="token punctuation">(</span>resp<span class="token punctuation">.</span>Body<span class="token punctuation">)</span>
    fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token function">string</span><span class="token punctuation">(</span>body<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br></div></div><h2 id="双向认证-对客户端证书进行校验">双向认证，对客户端证书进行校验 <a href="#双向认证-对客户端证书进行校验" class="header-anchor">#</a></h2> <p>服务端可以要求对客户端的证书进行校验，以更严格识别客户端的身份，限制客户端的访问。</p> <p>要对客户端数字证书进行校验，首先客户端需要先有自己的证书。</p> <p><code>golang</code>的<code>tls</code>要校验<code>ExtKeyUsage</code>，可以在生成时指定<code>extKeyUsage</code></p> <p>创建<code>client.ext</code>，内容： <code>extendedKeyUsage=clientAuth</code></p> <p><strong>生成客户端的私钥与证书</strong></p> <div class="language-bash line-numbers-mode"><pre class="language-bash"><code>openssl genrsa -out client.key <span class="token number">2048</span>
openssl req -new -key client.key -subj <span class="token string">&quot;/CN=wintrysec_com&quot;</span> -out client.csr
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfile client.ext -out client.crt -days <span class="token number">5000</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p><strong>服务端程序，<code>server.go</code>:</strong></p> <p>server端要校验client端的数字证书，并且加载用于校验数字证书的<code>ca.crt</code></p> <div class="language-go line-numbers-mode"><pre class="language-go"><code><span class="token comment">//server.go</span>
<span class="token keyword">package</span> main

<span class="token keyword">import</span> <span class="token punctuation">(</span>
    <span class="token string">&quot;crypto/tls&quot;</span>
    <span class="token string">&quot;crypto/x509&quot;</span>
    <span class="token string">&quot;fmt&quot;</span>
    <span class="token string">&quot;io/ioutil&quot;</span>
    <span class="token string">&quot;net/http&quot;</span>
<span class="token punctuation">)</span>

<span class="token keyword">type</span> myhandler <span class="token keyword">struct</span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token punctuation">(</span>h <span class="token operator">*</span>myhandler<span class="token punctuation">)</span> <span class="token function">ServeHTTP</span><span class="token punctuation">(</span>w http<span class="token punctuation">.</span>ResponseWriter<span class="token punctuation">,</span>r <span class="token operator">*</span>http<span class="token punctuation">.</span>Request<span class="token punctuation">)</span> 
<span class="token punctuation">{</span>
    fmt<span class="token punctuation">.</span><span class="token function">Fprintf</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span>
        <span class="token string">&quot;这是HTTPS页面，双向认证完成，我们可以通信了!\n&quot;</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    pool <span class="token operator">:=</span> x509<span class="token punctuation">.</span><span class="token function">NewCertPool</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    caCertPath <span class="token operator">:=</span> <span class="token string">&quot;ca.crt&quot;</span>

    caCrt<span class="token punctuation">,</span> err <span class="token operator">:=</span> ioutil<span class="token punctuation">.</span><span class="token function">ReadFile</span><span class="token punctuation">(</span>caCertPath<span class="token punctuation">)</span>
    <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
        fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">&quot;ReadFile err:&quot;</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
        <span class="token keyword">return</span>
    <span class="token punctuation">}</span>
    pool<span class="token punctuation">.</span><span class="token function">AppendCertsFromPEM</span><span class="token punctuation">(</span>caCrt<span class="token punctuation">)</span><span class="token comment">//加载用于校验数字证书的ca.crt</span>

    s <span class="token operator">:=</span> <span class="token operator">&amp;</span>http<span class="token punctuation">.</span>Server<span class="token punctuation">{</span>
        Addr<span class="token punctuation">:</span>    <span class="token string">&quot;:8081&quot;</span><span class="token punctuation">,</span>
        Handler<span class="token punctuation">:</span> <span class="token operator">&amp;</span>myhandler<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
        TLSConfig<span class="token punctuation">:</span> <span class="token operator">&amp;</span>tls<span class="token punctuation">.</span>Config<span class="token punctuation">{</span>
            ClientCAs<span class="token punctuation">:</span>  pool<span class="token punctuation">,</span><span class="token comment">//用于校验客户端证书</span>
            ClientAuth<span class="token punctuation">:</span> tls<span class="token punctuation">.</span>RequireAndVerifyClientCert<span class="token punctuation">,</span>
            <span class="token comment">//通过将tls.Config.ClientAuth赋值为tls.RequireAndVerifyClientCert来实现Server强制校验client端证书</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span>

    err <span class="token operator">=</span> s<span class="token punctuation">.</span><span class="token function">ListenAndServeTLS</span><span class="token punctuation">(</span><span class="token string">&quot;server.crt&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;server.key&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
        fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">&quot;ListenAndServeTLS err:&quot;</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br></div></div><p><strong>客户端程序，<code>client.go</code>:</strong></p> <div class="language-go line-numbers-mode"><pre class="language-go"><code><span class="token comment">//client.go</span>

<span class="token keyword">package</span> main
<span class="token keyword">import</span> <span class="token punctuation">(</span>
    <span class="token string">&quot;crypto/tls&quot;</span>
    <span class="token string">&quot;crypto/x509&quot;</span>
    <span class="token string">&quot;fmt&quot;</span>
    <span class="token string">&quot;io/ioutil&quot;</span>
    <span class="token string">&quot;net/http&quot;</span>
<span class="token punctuation">)</span>

<span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    pool <span class="token operator">:=</span> x509<span class="token punctuation">.</span><span class="token function">NewCertPool</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    caCertPath <span class="token operator">:=</span> <span class="token string">&quot;ca.crt&quot;</span>

    caCrt<span class="token punctuation">,</span> err <span class="token operator">:=</span> ioutil<span class="token punctuation">.</span><span class="token function">ReadFile</span><span class="token punctuation">(</span>caCertPath<span class="token punctuation">)</span>
    <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
        fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">&quot;ReadFile err:&quot;</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
        <span class="token keyword">return</span>
    <span class="token punctuation">}</span>
    pool<span class="token punctuation">.</span><span class="token function">AppendCertsFromPEM</span><span class="token punctuation">(</span>caCrt<span class="token punctuation">)</span>

    cliCrt<span class="token punctuation">,</span> err <span class="token operator">:=</span> tls<span class="token punctuation">.</span><span class="token function">LoadX509KeyPair</span><span class="token punctuation">(</span><span class="token string">&quot;client.crt&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;client.key&quot;</span><span class="token punctuation">)</span><span class="token comment">//需要加载client.key和client.crt用于server端连接时的证书校验 </span>
    <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
        fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">&quot;Loadx509keypair err:&quot;</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
        <span class="token keyword">return</span>
    <span class="token punctuation">}</span>

    tr <span class="token operator">:=</span> <span class="token operator">&amp;</span>http<span class="token punctuation">.</span>Transport<span class="token punctuation">{</span>
        TLSClientConfig<span class="token punctuation">:</span> <span class="token operator">&amp;</span>tls<span class="token punctuation">.</span>Config<span class="token punctuation">{</span>
            RootCAs<span class="token punctuation">:</span>      pool<span class="token punctuation">,</span>
            Certificates<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>tls<span class="token punctuation">.</span>Certificate<span class="token punctuation">{</span>cliCrt<span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span>
    client <span class="token operator">:=</span> <span class="token operator">&amp;</span>http<span class="token punctuation">.</span>Client<span class="token punctuation">{</span>Transport<span class="token punctuation">:</span> tr<span class="token punctuation">}</span>
    resp<span class="token punctuation">,</span> err <span class="token operator">:=</span> client<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span><span class="token string">&quot;https://localhost:8081&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
        fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">&quot;Get error:&quot;</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
        <span class="token keyword">return</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">defer</span> resp<span class="token punctuation">.</span>Body<span class="token punctuation">.</span><span class="token function">Close</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    body<span class="token punctuation">,</span> err <span class="token operator">:=</span> ioutil<span class="token punctuation">.</span><span class="token function">ReadAll</span><span class="token punctuation">(</span>resp<span class="token punctuation">.</span>Body<span class="token punctuation">)</span>
    fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token function">string</span><span class="token punctuation">(</span>body<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br></div></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">上次更新:</span> <span class="time">12/18/2021, 12:46:42 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev"><a href="/knowledge/base/network-http.html" class="prev"><i aria-label="icon: left" class="anticon anticon-left"><svg viewBox="64 64 896 896" focusable="false" data-icon="left" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 0 0 0 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"></path></svg></i>
        【网络基础】HTTP协议
      </a></span> <span class="next"><a href="/knowledge/base/network-route.html">
        【网络基础】路由协议
        <i aria-label="icon: right" class="anticon anticon-right"><svg viewBox="64 64 896 896" focusable="false" data-icon="right" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M765.7 486.8L314.9 134.7A7.97 7.97 0 0 0 302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 0 0 0-50.4z"></path></svg></i></a></span></p></div> </main> <!----></div><div class="global-ui"></div></div>
    <script src="/assets/js/app.f7464420.js" defer></script><script src="/assets/js/2.26207483.js" defer></script><script src="/assets/js/19.19350186.js" defer></script>
  </body>
</html>